package com.gitee.alg.sort

/**
 * Project Name: alg
 * Des: 快速排序
 *      1.从数列中挑出一个元素，称为 "基准"（pivot）;
 *      2.重新排序数列，所有元素比基准值小的摆放在基准前面，所有元素比基准值大的摆在基准的后面（相同的数可以到任一边）。
 *      在这个分区退出之后，该基准就处于数列的中间位置。这个称为分区（partition）操作；
 *      3. 递归地（recursive）把小于基准值元素的子数列和大于基准值元素的子数列排序；
 * Package:com.gitee.alg.sort
 * @author Arlo Sun
 * @date 2021/4/27 - 9:21
 */
class QuickSort<T : Comparable<T>>(override val compare: (T, T) -> Boolean) : ArraySort<T> {


    override fun sort(array: Array<T>, ascend: Boolean): Array<T> {
        return quickSort(array, 0, array.size - 1)
    }


    private fun quickSort(array: Array<T>, left: Int, right: Int): Array<T> {
        if (left < right) {
            val pivot = partition(array, left, right)
            quickSort(array, left, pivot - 1)
            quickSort(array, pivot + 1, right)
        }
        return array
    }


    private fun partition(array: Array<T>, left: Int, right: Int): Int {

        //以left指向的元素作为基准
        val pivot = array[left]
        var pivotIndex = left + 1

        for (i in (left + 1)..right) {
            if (compare(pivot, array[i])) {
                array.swap(pivotIndex++, i)
            }
        }

        //left为最后一个小于标识的的元素准备
        array.swap(left, --pivotIndex)

        return pivotIndex
    }
}